﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Snowdreamist.ComponentModel;

namespace Snowdreamist.Windows.Navigation.Primitives
{
    /// <summary>
    /// Don't provide thread-safe
    /// </summary>
    /// <typeparam name="TEntry"></typeparam>
    public abstract class JournalBase<TEntry> : NotifyPropertyChangedBase where TEntry : class
    {
        public JournalBase()
        {
            this.Clear();
        }

        #region CanGoBack

        private bool _CanGoBack;

        /// <summary>
        /// CanGoBack
        /// </summary>
        public virtual bool CanGoBack
        {
            get { return this._CanGoBack; }
            set
            {
                if (this._CanGoBack != value)
                {
                    this._CanGoBack = value;
                    this.OnPropertyChanged("CanGoBack");
                }
            }
        }

        #endregion CanGoBack

        #region CanGoForward

        private bool _CanGoForward;

        /// <summary>
        /// CanGoForward
        /// </summary>
        public virtual bool CanGoForward
        {
            get { return this._CanGoForward; }
            set
            {
                if (this._CanGoForward != value)
                {
                    this._CanGoForward = value;
                    this.OnPropertyChanged("CanGoForward");
                }
            }
        }

        #endregion CanGoForward

        public virtual bool GoBack()
        {
            if (this.CanGoBack)
                return this.NavigateTo(this._entries[this._currentIndex - 1]);
            else
                return false;
        }

        public virtual bool GoForward()
        {
            if (this.CanGoForward)
                return this.NavigateTo(this._entries[this._currentIndex + 1]);
            else
                return false;
        }

        public virtual void Clear()
        {
            this._currentIndex = -1;
            this._entries.Clear();
        }

        public virtual bool NavigateTo(TEntry entry)
        {
            if (entry == null)
                throw new ArgumentNullException("entry");

            int index = this._entries.IndexOf(entry);
            if (index != -1)
            {
                // navigate to it
                this._currentIndex = index;
            }
            else
            {
                // add (cut is necessary)
                for (int i = this._entries.Count - 1; i > index; --i)
                    this._entries.RemoveAt(i);
                this._entries.Add(entry);
            }

            this.AdjustNavigationChange();

            return true;
        }

        public IEnumerable<TEntry> Entries
        {
            get
            {
                return this._entries.ToArray();
            }
        }

        public event EventHandler<JournalChangedEventArgs<TEntry>> JournalChanged;

        #region Current

        private TEntry _Current;

        /// <summary>
        /// Current
        /// </summary>
        public TEntry Current
        {
            get { return this._Current; }

            private set
            {
                this._Current = value;
                this.OnPropertyChanged("Current");
                this.OnJournalChanged(value);
            }
        }

        #endregion Current

        #region protected

        protected virtual void AdjustNavigationChange()
        {
            // set current
            this.Current = this._entries[this._currentIndex];
            // can go back
            this.CanGoBack = this._currentIndex > 0;
            // can go forward
            this.CanGoForward = this._currentIndex < this._entries.Count - 1;
        }

        protected virtual void OnJournalChanged(TEntry newEntry)
        {
            if (this.JournalChanged != null)
                this.JournalChanged(this, new JournalChangedEventArgs<TEntry>(newEntry));
        }

        #endregion protected

        #region private

        private int _currentIndex;

        private readonly List<TEntry> _entries = new List<TEntry>();

        #endregion private
    }
}